// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package traffic

import (
	"apiote.xyz/p/szczanieckiej/transformers"

	"bufio"
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"golang.org/x/text/transform"
	"golang.org/x/tools/blog/atom"
)

type BrusselsStibMivb struct {
	client http.Client
}

func (BrusselsStibMivb) getTimezone() *time.Location {
	l, _ := time.LoadLocation("Europe/Brussels")
	return l
}

func (BrusselsStibMivb) ConvertVehicles() ([]Vehicle, error) {
	return []Vehicle{}, nil
}

func (z BrusselsStibMivb) GetVersions(date time.Time, timezone *time.Location) ([]Version, error) {
	url := "https://stibmivb.opendatasoft.com/explore/dataset/gtfs-files-production/atom/"
	response, err := z.client.Get(url)
	if err != nil {
		return []Version{}, fmt.Errorf("GetVersions: cannot GET ‘%s’: %w", url, err)
	}

	decoder := xml.NewDecoder(response.Body)
	versionsFeed := atom.Feed{}
	decoder.Decode(&versionsFeed)
	if len(versionsFeed.Entry) == 0 {
		return []Version{}, nil
	}
	updated, err := time.Parse("2006-01-02T15:04:05.000000-07:00", string(versionsFeed.Entry[0].Updated))
	validityString := updated.Format("20060102") + "_99991231"

	version, err := MakeVersionTimezone(validityString, timezone)
	if err != nil {
		return nil, err
	}
	version.Link = "https://stibmivb.opendatasoft.com/api/explore/v2.1/catalog/datasets/gtfs-files-production/alternative_exports/gtfszip/"
	versions := []Version{version}
	return versions, nil
}

func (BrusselsStibMivb) String() string {
	return "brussels_stib_mivb"
}

func (BrusselsStibMivb) RealtimeFeeds() map[RealtimeFeedType]string {
	return map[RealtimeFeedType]string{}
}

func (BrusselsStibMivb) Transformer() transform.Transformer {
	return transform.Chain(transformers.TransformerFR, transformers.TransformerNL)
}

func (BrusselsStibMivb) Name() string {
	return "Brussels STIB-MIVB"
}

func (BrusselsStibMivb) Flags() FeedFlags {
	return FeedFlags{
		Headsign:     HeadsignTripHeadsing,
		StopIdFormat: "{{stop_id}}",
		StopName:     "{{stop_name}} [{{stop_id}}]",
		LineName:     "{{route_short_name}}",
	}
}

func (BrusselsStibMivb) FeedPrepareZip(path string) error {
	// add feed info
	feedInfoFile, err := os.OpenFile(filepath.Join(path, "feed_info.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening feedInfo file: %w", err)
	}
	defer feedInfoFile.Close()
	w := csv.NewWriter(feedInfoFile)
	err = w.Write([]string{"feed_publisher_name", "feed_publisher_url", "feed_lang", "default_lang"})
	if err != nil {
		return fmt.Errorf("while writing header: %w", err)
	}
	err = w.Write([]string{"STIB-MIVB", "https://www.stib-mivb.be", "mul", "fr"})
	if err != nil {
		return fmt.Errorf("while writing record: %w", err)
	}
	w.Flush()

	// fix number of fields in stops
	stopsFile, err := os.Open(filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while opening stops file: %w", err)
	}
	defer stopsFile.Close()
	stops2File, err := os.OpenFile(filepath.Join(path, "stops2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening stops2 file: %w", err)
	}
	defer stops2File.Close()
	r := csv.NewReader(bufio.NewReader(stopsFile))
	r.FieldsPerRecord = -1
	w = csv.NewWriter(stops2File)
	header, err := r.Read()
	if err != nil {
		return fmt.Errorf("while reading stops header: %w", err)
	}
	fields := map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing stops header: %w", err)
	}

	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a stop record: %w", err)
		}
		for len(record) < len(header) {
			record = append(record, "")
		}
		err = w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing a stop record: %w", err)
		}
	}
	w.Flush()
	err = os.Remove(filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while removing stops: %w", err)
	}
	err = os.Rename(filepath.Join(path, "stops2.txt"), filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while renaming stops: %w", err)
	}
	return nil
}

func (BrusselsStibMivb) QRInfo() (string, QRLocation, string) {
	return "", QRLocationNone, ""
}
